﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using SteamGroupPlayers.Model;
using SteamGroupPlayers.Utilities;

namespace SteamGroupPlayers.ViewModel
{
	public class GroupViewModel : NotifyPropertyChanged, IDisposable
	{
		#region Fields
		private Game _filterGame = null;
		private bool _recent = true;
		private Loader _loader = new Loader();
		#endregion

		#region Properties
		public bool IsBusy { get; set; }
		public bool IsIndeterminate { get; set; }
		public double Progress { get; set; }
		public string GroupName { get; set; }
		public List<Player> PlayerList{ get; set;}
		public List<Game> GameList { get; set; }
		public bool GameListEnabled { get; set; }
		public Game FilterGame 
		{
			get { return _filterGame; }
			set
			{
				if (_filterGame == value)
					return;

				_filterGame = value;
				RaisePropertyChanged("FilterGame");
				UpdateFilter();
			}
		}
		public bool Recent
		{
			get { return _recent; }
			set
			{
				if (_recent == value)
					return;

				_recent = value;
				RaisePropertyChanged("Recent");
				UpdateFilter();
			}
		}
		public ImageSource Warning { get; set; }
		public bool HasExceptions { get; set; }
		public string GroupAvatar { get; set; }
		public List<Tuple<DateTime, string, Exception>> Exceptions { get; set; }
		public int PlayersToLoad { get; set; }
		public int LoadedPlayers { get; set; }
		#endregion

		#region Commands
		private ICommand _setGroupCommand;
		public ICommand SetGroupCommand
		{
			get
			{
				if (_setGroupCommand == null)
					_setGroupCommand = new RelayCommand<string>(this.Download);

				return _setGroupCommand;
			}
		}

		private ICommand _copyExceptionsCommand;
		public ICommand CopyExceptionsCommand
		{
			get
			{
				if (_copyExceptionsCommand == null)
					_copyExceptionsCommand = new RelayCommand(() =>
						{
							string txt = "";
							foreach (Tuple<DateTime, string, Exception> ex in Exceptions)
								txt += ex.Item3.Message + "\r\n" + String.Format(" [{0:yyyy-MM-dd HH:mm:ss}]: {1}", ex.Item1, ex.Item2) + "\r\n" + ex.Item3.StackTrace + "\r\n";
							Clipboard.SetText(txt);
						});

				return _copyExceptionsCommand;
			}
		}
		#endregion

		#region Constructors
		public GroupViewModel()
		{

			var warning = System.Drawing.SystemIcons.Warning;
			Warning = System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(warning.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
			Exceptions = new List<Tuple<DateTime, string, Exception>>();

			Messenger.Default.Register<int>(this, "PlayerQueue", OnPlayerQueueMessage);
			Messenger.Default.Register<Exception>(this, OnException);

			GameListEnabled = false;

			_loader.OnCancel += new Loader.CanceledEventHandler(_loader_OnCancel);
			_loader.OnGroupDataLoaded += new Loader.GroupDataLoadedEventHandler(_loader_OnGroupDataLoaded);
			_loader.OnPlayersLoaded += new Loader.GroupPlayersLoadedEventHandler(_loader_OnPlayersLoaded);
			_loader.OnGroupDataProgress += new Loader.GroupDataProgressHandler(_loader_OnGroupDataProgress);
		}
		#endregion

		#region Methods
		public void Dispose()
		{
			_loader.Dispose();
			Messenger.Default.Unregister(this);
		}
		
		void _loader_OnCancel(object sender, EventArgs e)
		{
			IsBusy = false;
			PlayerList = null;
			GameList = null;
			GroupName = null;
			GameListEnabled = false;
			LoadedPlayers = 0;
			PlayersToLoad = 1;
			GroupAvatar = null;

			GC.Collect();
		}

		void _loader_OnPlayersLoaded(object sender, GroupPlayersLoadedEventArgs e)
		{
			GameList = e.Games;
			GameListEnabled = true;
		}

		void _loader_OnGroupDataLoaded(object sender, GroupDataLoadedEventArgs e)
		{
			IsBusy = false;

			if (!e.HasError)
			{
				GroupName = e.Name;
				GroupAvatar = e.Avatar;
				PlayerList = e.Players;
			}
		}

		void _loader_OnGroupDataProgress(object sender, GroupDataProgressEventArgs e)
		{
			GroupName = e.Group;
			IsIndeterminate = false;
			Progress = e.Progress;
		}

		private void OnPlayerQueueMessage(int players)
		{
			if (PlayerList != null)
			{
				PlayersToLoad = PlayerList.Count;
				LoadedPlayers = PlayerList.Where(p => !p.IsLoading).Count();
			}

			UpdateFilter();
		}

		private void UpdateFilter()
		{
			if (PlayerList == null)
				return;

			if (_filterGame == null || _filterGame.AppID == 0)
				if (_recent)
					PlayerList = PlayerList.OrderBy(p => p.IsLoading).ThenByDescending(p => p.SumRecent).ThenByDescending(p => p.SumAll).ToList();
				else
					PlayerList = PlayerList.OrderBy(p => p.IsLoading).ThenByDescending(p => p.SumAll).ThenByDescending(p => p.SumRecent).ToList();
			else
				if(_recent)
					PlayerList = PlayerList.OrderBy(p => p.IsLoading).ThenByDescending(p => p.Played == null ? 0 : p.Played.Where(g => g.AppID == _filterGame.AppID).Select(g => g.PlayedRecent).FirstOrDefault()).ThenByDescending(p => p.Played == null ? 0 : p.Played.Where(g => g.AppID == _filterGame.AppID).Select(g => g.PlayedAll).FirstOrDefault()).ToList();
				else
					PlayerList = PlayerList.OrderBy(p => p.IsLoading).ThenByDescending(p => p.Played == null ? 0 : p.Played.Where(g => g.AppID == _filterGame.AppID).Select(g => g.PlayedAll).FirstOrDefault()).ThenByDescending(p => p.Played == null ? 0 : p.Played.Where(g => g.AppID == _filterGame.AppID).Select(g => g.PlayedRecent).FirstOrDefault()).ToList();
		}

		private void OnException(Exception ex)
		{
			Exceptions.Add(Tuple.Create<DateTime, string, Exception>(DateTime.Now, GroupName, ex));
			HasExceptions = true;
		}

		private void Download(string group)
		{
			if (String.IsNullOrEmpty(group))
				return;

			bool isGame = false;
			group = group.Trim();
			if (group.StartsWith("game:"))
			{
				group = group.Replace("game:", "").Trim();
				isGame = true;
			}

			GameListEnabled = false;
			PlayersToLoad = 1;
			LoadedPlayers = 0;

			_loader.LoadGroup(group, isGame);
			IsBusy = true;
			IsIndeterminate = true;
			Progress = 0;
		} 
		#endregion
	}
}